home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Moscow ML 1.31 / source code / mosml / src / runtime / debugcom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-03  |  9.0 KB  |  344 lines  |  [TEXT/R*ch]

  1. /* Communication with a debugger. */
  2.  
  3. #include <stdio.h>
  4. #include "misc.h"
  5. #include "debugger.h"
  6. #include "mlvalues.h"
  7. #include "fail.h"
  8. #include "stacks.h"
  9. #include "io.h"
  10. #include "debugcom.h"
  11.  
  12. unsigned long event_count;
  13. value * trap_barrier;
  14. int enable_sigint;
  15.  
  16. #ifndef HAS_SOCKETS
  17.  
  18. void debugger_init(address)
  19.      char * address;
  20. {
  21. }
  22.  
  23. int debugger(event)
  24.      int event;
  25. {
  26.   return 0;
  27. }
  28.  
  29. #else
  30.  
  31. #include <sys/types.h>
  32. #include <sys/socket.h>
  33. #include <sys/un.h>
  34. #include <netinet/in.h>
  35. #include <netdb.h>
  36.  
  37. extern code_t start_code;
  38. extern asize_t code_size;
  39.  
  40. #define REP_EVENT 'e'
  41. #define REP_BREAKPOINT 'b'
  42. #define REP_EXITED 'x'
  43. #define REP_TRAP 's'
  44. #define REP_CHECKPOINT_DONE 'd'
  45. #define REP_CHECKPOINT_FAILED 'f'
  46.  
  47. #define REQ_SET_EVENT 'e'
  48. #define REQ_SET_INSTR 'i'
  49. #define REQ_CHECKPOINT 'c'
  50. #define REQ_WAIT 'w'
  51. #define REQ_GO 'g'
  52. #define REQ_RESTART 'r'
  53. #define REQ_STOP 's'
  54. #define REQ_MOVE_FRAME 'f'
  55. #define REQ_SET_TRAP_BARRIER 'b'
  56. #define REQ_GET_LOCAL 'L'
  57. #define REQ_GET_GLOBAL 'G'
  58. #define REQ_GET_ACCU 'A'
  59. #define REQ_GET_OBJ 'O'
  60. #define REQ_GET_CLOSURE_CODE 'C'
  61. #define REQ_GET_HEADER 'H'
  62. #define REQ_GET_FIELD 'F'
  63. #define REQ_SET_FIELD 'S'
  64. #define REQ_SET_GLOBAL 'I'
  65.  
  66. static int sock_domain;         /* Socket domain for the debugger */
  67. static union {                  /* Socket address for the debugger */
  68.   struct sockaddr s_gen;
  69.   struct sockaddr_un s_unix;
  70.   struct sockaddr_in s_inet;
  71. } sock_addr;
  72. static int sock_addr_len;       /* Length of sock_addr */
  73.  
  74. static int dbg_socket = -1;     /* The socket connected to the debugger */
  75. static struct channel * dbg_in; /* Input channel on the socket */
  76. static struct channel * dbg_out;/* Output channel on the socket */
  77.  
  78. #define CONNECT_STARTUP 1
  79. #define CONNECT_CHILD 0
  80.  
  81. static void open_connection(connect_type)
  82.      int connect_type;
  83. {
  84.   dbg_socket = socket(sock_domain, SOCK_STREAM, 0);
  85.   if (dbg_socket == -1) {
  86.     perror("socket failed");
  87.     exit(2);
  88.   }
  89.   if (connect(dbg_socket, &sock_addr.s_gen, sock_addr_len) == -1) {
  90.     perror("connection to debugger failed");
  91.     exit(2);
  92.   }
  93.   dbg_in = open_descr(dbg_socket);
  94.   dbg_out = open_descr(dbg_socket);
  95.   if (connect_type)
  96.     putword(dbg_out, 0);
  97.   putword(dbg_out, getpid());
  98.   flush(dbg_out);
  99.   if (connect_type)
  100.     enable_sigint = getword(dbg_in);
  101. }
  102.  
  103. static void close_connection()
  104. {
  105.   close(dbg_socket);
  106. }
  107.  
  108. void debugger_init(address)
  109.      char * address;
  110. {
  111.   char * port, * p;
  112.   struct hostent * host;
  113.   int n;
  114.  
  115.   /* Parse the address */
  116.   port = NULL;
  117.   for (p = address; *p != 0; p++) {
  118.     if (*p == ':') { *p = 0; port = p+1; break; }
  119.   }
  120.   if (port == NULL) {
  121.     /* Unix domain */
  122.     sock_domain = PF_UNIX;
  123.     sock_addr.s_unix.sun_family = AF_UNIX;
  124.     strncpy(sock_addr.s_unix.sun_path, address,
  125.             sizeof(sock_addr.s_unix.sun_path));
  126.     sock_addr_len = sizeof(sock_addr.s_unix.sun_family) + strlen(address);
  127.   } else {
  128.     /* Internet domain */
  129.     sock_domain = PF_INET;
  130.     for (p = (char *) &sock_addr.s_inet, n = sizeof(sock_addr.s_inet);
  131.          n > 0; n--) *p++ = 0;
  132.     sock_addr.s_inet.sin_family = AF_INET;
  133.     sock_addr.s_inet.sin_addr.s_addr = inet_addr(address);
  134.     if (sock_addr.s_inet.sin_addr.s_addr == -1) {
  135.       host = gethostbyname(address);
  136.       if (host == NULL)
  137.         fatal_error_arg("Unknown debugging host %s\n", address);
  138.       bcopy(host->h_addr, &sock_addr.s_inet.sin_addr, host->h_length);
  139.     }
  140.     sock_addr.s_inet.sin_port = htons(atoi(port));
  141.     sock_addr_len = sizeof(sock_addr.s_inet);
  142.   }
  143.   open_connection(CONNECT_STARTUP);
  144.   debugger(PROGRAM_START);
  145. }
  146.  
  147. static value getval(chan)
  148.      struct channel * chan;
  149. {
  150.   value res;
  151.   if (really_getblock(chan, (char *) &res, sizeof(res)) == 0)
  152.     mlraise(Atom(END_OF_FILE_EXN)); /* Bad, but consistent with getword */
  153.   return res;
  154. }
  155.  
  156. static void putval(chan, val)
  157.      struct channel * chan;
  158.      value val;
  159. {
  160.   putblock(chan, (char *) &val, sizeof(val));
  161. }
  162.  
  163. #define Cache(rsp) \
  164.   ((value *)((char *) (rsp) + sizeof(struct return_frame)))
  165. #define Cache_size(rsp) (((struct return_frame *)(rsp)) -> cache_size)
  166. #define Pc(rsp) (((struct return_frame *)(rsp)) -> pc)
  167. #define Env(rsp) (((struct return_frame *)(rsp)) -> env)
  168. #define Trap_pointer(rsp) (((struct trap_frame *)(rsp)) -> tp)
  169.  
  170. int debugger(event)
  171.      int event;
  172. {
  173.   int frame_number;
  174.   value * frame;
  175.   struct trap_frame * trap_frame;
  176.   long i, pos;
  177.   mlsize_t size;
  178.   int cache_size;
  179.   value val;
  180.   value * p;
  181.  
  182.   if (dbg_socket == -1) return;  /* Not connected to a debugger. */
  183.  
  184.   /* Report the event to the debugger */
  185.   switch(event) {
  186.   case PROGRAM_START:           /* Nothing to report */
  187.     goto command_loop;
  188.   case EVENT:
  189.     putch(dbg_out, REP_EVENT);
  190.     break;
  191.   case BREAKPOINT:
  192.     putch(dbg_out, REP_BREAKPOINT);
  193.     break;
  194.   case PROGRAM_EXIT:
  195.     putch(dbg_out, REP_EXITED);
  196.     break;
  197.   case TRAP_BARRIER:
  198.     putch(dbg_out, REP_TRAP);
  199.     break;
  200.   }
  201.   putword(dbg_out, event_count);
  202.   putword(dbg_out, ret_stack_high - extern_rsp);
  203.   putword(dbg_out, Pc(extern_rsp) - start_code);
  204.   flush(dbg_out);
  205.  
  206.  command_loop:
  207.   /* Reset current frame */
  208.   frame_number = 0;
  209.   frame = extern_rsp;
  210.   trap_frame = tp;
  211.   
  212.   /* Read and execute the commands sent by the debugger */
  213.   while(1) {
  214.     switch(getch(dbg_in)) {
  215.     case REQ_SET_EVENT:         /* Set the event bit on an instruction. */
  216.       pos = getword(dbg_in);
  217.       Assert(pos >= 0 && pos < code_size);
  218.       start_code[pos] |= 0x80;
  219.       break;
  220.     case REQ_SET_INSTR:         /* Overwrite an instruction. */
  221.       pos = getword(dbg_in);
  222.       Assert(pos >= 0 && pos < code_size);
  223.       putch(dbg_out, start_code[pos]);
  224.       i = getch(dbg_in);
  225.       start_code[pos] = i;
  226.       flush(dbg_out);
  227.       break;
  228.     case REQ_CHECKPOINT:        /* Checkpoint the runtime system. */
  229.       i = fork();
  230.       if (i == -1) {
  231.         putch(dbg_out, REP_CHECKPOINT_FAILED);
  232.         flush(dbg_out);
  233.       } else if (i == 0) {
  234.     close_connection();    /* Close parent connection. */
  235.     open_connection(CONNECT_CHILD);
  236.       } else {
  237.     putch(dbg_out, REP_CHECKPOINT_DONE);
  238.     putword(dbg_out, i);
  239.     flush(dbg_out);
  240.       }
  241.       break;
  242.     case REQ_GO:                /* Run the program for N events. */
  243.       event_count = getword(dbg_in);
  244.       return -1;
  245.     case REQ_RESTART:                /* Same as REQ_GO, but restart on */
  246.       i = getch(dbg_in);             /* a given instruction, so as to skip */
  247.       event_count = getword(dbg_in); /* a breakpoint. */
  248.       return i;
  249.     case REQ_STOP:              /* Exit prematurely */
  250.       exit(0);
  251.       break;
  252.     case REQ_WAIT:        /* Wait for the child to die */
  253.       wait(NULL);
  254.       break;
  255.     case REQ_MOVE_FRAME:        /* Move to a frame and return the pc */
  256.       i = getword(dbg_in);
  257.       if (i < frame_number) {
  258.         frame_number = 0;
  259.         frame = extern_rsp;
  260.         trap_frame = tp;
  261.       }
  262.       while (frame < ret_stack_high && i > frame_number) {
  263.         /* Skip the return frames */
  264.         Assert(frame < ret_stack_high);
  265.         cache_size = Cache_size(frame);
  266.         frame = Cache(frame) + cache_size;
  267.         while (frame == (value *) trap_frame) { /* Skip the trap frames */
  268.           Assert(frame < ret_stack_high);
  269.           trap_frame = Trap_pointer(frame);
  270.           cache_size = Cache_size(frame);
  271.           frame = Cache(frame) + cache_size;
  272.         }
  273.         frame_number++;
  274.       }
  275.       putword(dbg_out, ret_stack_high - frame);
  276.       if (frame >= ret_stack_high)
  277.         putword(dbg_out, -1);
  278.       else
  279.         putword(dbg_out, Pc(frame) - start_code);
  280.       flush(dbg_out);
  281.       break;
  282.     case REQ_SET_TRAP_BARRIER:  /* Set the trap barrier */
  283.       i = getword(dbg_in);
  284.       trap_barrier = ret_stack_high - i;
  285.       break;
  286.     case REQ_GET_LOCAL:         /* Return the value of the Nth variable */
  287.       i = getch(dbg_in);
  288.       cache_size = Cache_size(frame);
  289.       if (i < cache_size)
  290.         putval(dbg_out, Cache(frame)[i]);
  291.       else {
  292.         i -= cache_size;
  293.         Assert(i < Wosize_val(Env(frame)));
  294.         putval(dbg_out, Field(Env(frame), i));
  295.       }
  296.       flush(dbg_out);
  297.       break;
  298.     case REQ_GET_GLOBAL:        /* Return the value of the Nth global */
  299.       i = getword(dbg_in);
  300.       putval(dbg_out, Field(global_data, i));
  301.       flush(dbg_out);
  302.       break;
  303.     case REQ_GET_ACCU:
  304.       putval(dbg_out, *extern_asp);
  305.       flush(dbg_out);
  306.       break;
  307.     case REQ_GET_OBJ:
  308.       val = getval(dbg_in);
  309.       putword(dbg_out, Hd_val(val));
  310.       for (size = Wosize_val(val), p = &Field(val, 0); size > 0; size--, p++)
  311.         putval(dbg_out, *p);
  312.       flush(dbg_out);
  313.       break;
  314.     case REQ_GET_CLOSURE_CODE:
  315.       val = getval(dbg_in);
  316.       putword(dbg_out, Code_val(val) - start_code);
  317.       flush(dbg_out);
  318.       break;
  319.     case REQ_GET_HEADER:
  320.       val = getval(dbg_in);
  321.       putword(dbg_out, Hd_val(val));
  322.       flush(dbg_out);
  323.       break;
  324.     case REQ_GET_FIELD:
  325.       val = getval(dbg_in);
  326.       i = getword(dbg_in);
  327.       putval(dbg_out, Field(val, i));
  328.       flush(dbg_out);
  329.       break;
  330.     case REQ_SET_FIELD:
  331.       val = getval(dbg_in);
  332.       i = getword(dbg_in);
  333.       Field(val, i) = getval(dbg_in);
  334.       break;
  335.     case REQ_SET_GLOBAL:
  336.       i = getword(dbg_in);
  337.       Field(global_data, i) = getval(dbg_in);
  338.       break;
  339.     }
  340.   }
  341. }
  342.  
  343. #endif
  344.